using System;

namespace Utilities
{
    /// <summary>
    /// Helper class that implements the recommended IDisposable design pattern.
    /// </summary>
    [Serializable]
    public abstract class DisposableBase : IDisposable {
        private bool m_Disposed;
        private string m_ObjectName;

        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Method called when disposing or finalizing.
        /// </summary>
        /// <param name="disposing">
        /// If <em>true</em>, this was called by the <see cref="Dispose()"/> method, and so managed and unmanaged resources
        /// should be cleaned up. If <em>false</em>, this was called by the finalizer, so only unmanaged resources should
        /// be cleaned up.
        /// </param>
        /// <remarks>
        /// As a guide, all methods of a class inheriting <see cref="IDisposable"/> should check if it is disposed
        /// when every non-private method is called using the provided method <see cref="CheckDisposed"/>.
        /// </remarks>
        protected virtual void Dispose(bool disposing) {
            m_Disposed = true;
        }

        ~DisposableBase() {
            Dispose(false);
        }

        /// <summary>
        /// Returns a value indicating if this instance has been disposed.
        /// </summary>
        public bool IsDisposed {
            get { return m_Disposed; }
        }

        /// <summary>
        /// Gets and sets the object name to use for any thrown <see cref="ObjectDisposedException"/>s. The default
        /// is the Name property of <see cref="Object.GetType()"/>.
        /// </summary>
        protected string ObjectName {
            get { return !String.IsNullOrEmpty(m_ObjectName) ? m_ObjectName : GetType().Name; }
            set { m_ObjectName = value; }
        }

        /// <summary>
        /// Throws <see cref="ObjectDisposedException"/> if this instance has been disposed.
        /// </summary>
        /// <exception cref="ObjectDisposedException">This instance has been disposed.</exception>
        protected void CheckDisposed() {
            if (m_Disposed)
                throw new ObjectDisposedException(ObjectName);
        }
    }
}
